/*****************************************************************************
 * hal_cx32_gpio.c
 *
 * Copyright (C) 2019 Jeasonvor <1101627719@qq.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 ****************************************************************************/

/*****************************************************************************
 * Included Files
 ****************************************************************************/

#include "plum_hal_gpio.h"
#include "kernel/plum_kernel_api.h"

/*****************************************************************************
 * Trace Definitions
 ****************************************************************************/

/*****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/*****************************************************************************
 * Private Types
 ****************************************************************************/

/*****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

/*****************************************************************************
 * Private Data
 ****************************************************************************/

/*****************************************************************************
 * Public Data
 ****************************************************************************/

/*****************************************************************************
 * Private Functions
 ****************************************************************************/

static void gpio_clk_enable(plum_u32 id)
{
    switch (CX32L003_GPIO_PORT(id)) {
#if defined(GPIOA)
        case 'A':
            __HAL_RCC_GPIOA_CLK_ENABLE();
            break;
#endif

#if defined(GPIOB)
        case 'B':
            __HAL_RCC_GPIOB_CLK_ENABLE();
            break;
#endif

#if defined(GPIOC)
        case 'C':
            __HAL_RCC_GPIOC_CLK_ENABLE();
            break;
#endif

#if defined(GPIOD)
        case 'D':
            __HAL_RCC_GPIOD_CLK_ENABLE();
            break;
#endif

#if defined(GPIOE)
        case 'E':
            __HAL_RCC_GPIOE_CLK_ENABLE();
            break;
#endif

#if defined(GPIOF)
        case 'F':
            __HAL_RCC_GPIOF_CLK_ENABLE();
            break;
#endif
    }
}

static GPIO_TypeDef *gpio_id2port(plum_u32 id)
{
    GPIO_TypeDef *GPIOx = NULL;

    switch (CX32L003_GPIO_PORT(id)) {
#if defined(GPIOA)
        case 'A':
            GPIOx = GPIOA;
            break;
#endif

#if defined(GPIOB)
        case 'B':
            GPIOx = GPIOB;
            break;
#endif

#if defined(GPIOC)
        case 'C':
            GPIOx = GPIOC;
            break;
#endif

#if defined(GPIOD)
        case 'D':
            GPIOx = GPIOD;
            break;
#endif

#if defined(GPIOE)
        case 'E':
            GPIOx = GPIOE;
            break;
#endif

#if defined(GPIOF)
        case 'F':
            GPIOx = GPIOF;
            break;
#endif

        default:
            break;
    }

    return (GPIOx);
}

static plum_u16 gpio_id2pin(plum_u32 id)
{
    plum_u16 pin = 0xFFFF;

    switch (CX32L003_GPIO_PIN(id)) {
#if defined(GPIO_PIN_0)
        case 0:
            pin = GPIO_PIN_0;
            break;
#endif

#if defined(GPIO_PIN_1)
        case 1:
            pin = GPIO_PIN_1;
            break;
#endif

#if defined(GPIO_PIN_2)
        case 2:
            pin = GPIO_PIN_2;
            break;
#endif

#if defined(GPIO_PIN_3)
        case 3:
            pin = GPIO_PIN_3;
            break;
#endif

#if defined(GPIO_PIN_4)
        case 4:
            pin = GPIO_PIN_4;
            break;
#endif

#if defined(GPIO_PIN_5)
        case 5:
            pin = GPIO_PIN_5;
            break;
#endif

#if defined(GPIO_PIN_6)
        case 6:
            pin = GPIO_PIN_6;
            break;
#endif

#if defined(GPIO_PIN_7)
        case 7:
            pin = GPIO_PIN_7;
            break;
#endif
    }

    return (pin);
}

/*****************************************************************************
 * Public Functions
 ****************************************************************************/

plum_s32 plum_hal_gpio_mode(plum_u32 id, plum_hal_gpio_mode_t gpio)
{
    GPIO_TypeDef *GPIOx = gpio_id2port(id);
    if (!GPIOx) {
        return (PLUM_ECODE_EPARA);
    }

    plum_u16 pin = gpio_id2pin(id);
    if (pin == 0xFFFF) {
        return (PLUM_ECODE_EPARA);
    }

    gpio_clk_enable(id);

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin  = pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    //	GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    //	GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;

    switch (mode) {
        case PLUM_HAL_GPIO_MODE_ANALOG:
            GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
            break;

        case PLUM_HAL_GPIO_MODE_INPUT:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            break;

        case PLUM_HAL_GPIO_MODE_INPUT_UP:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            break;

        case PLUM_HAL_GPIO_MODE_INPUT_DOWN:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
            break;

        case PLUM_HAL_GPIO_MODE_OUT_PP:
            GPIO_InitStruct.Mode        = GPIO_MODE_OUTPUT;
            GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
            GPIO_InitStruct.OpenDrain   = GPIO_PUSHPULL;
            break;

        case PLUM_HAL_GPIO_MODE_OUT_OD:
            GPIO_InitStruct.Mode        = GPIO_MODE_OUTPUT;
            GPIO_InitStruct.OpenDrain   = GPIO_OPENDRAIN;
            GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
            break;

        case PLUM_HAL_GPIO_MODE_OUT_OD_UP:
            GPIO_InitStruct.Mode        = GPIO_MODE_OUTPUT;
            GPIO_InitStruct.OpenDrain   = GPIO_OPENDRAIN;
            GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
            GPIO_InitStruct.Pull        = GPIO_PULLUP;
            break;

        case PLUM_HAL_GPIO_MODE_OUT_OD_DOWN:
            GPIO_InitStruct.Mode        = GPIO_MODE_OUTPUT;
            GPIO_InitStruct.OpenDrain   = GPIO_OPENDRAIN;
            GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
            GPIO_InitStruct.Pull        = GPIO_PULLDOWN;
            break;

        default:
            break;
    }

    if(HAL_OK != HAL_GPIO_Init(GPIOx, &GPIO_InitStruct){
        return (PLUM_ECODE_UNK); 
    }
	
	return (PLUM_ECODE_OK );
}

plum_s32 plum_hal_gpio_write(plum_u32 id, plum_hal_gpio_sta_t state)
{
    GPIO_TypeDef *GPIOx = gpio_id2port(id);
    if (!GPIOx) {
        return (PLUM_ECODE_EPARA);
    }

    plum_u16 pin = gpio_id2pin(id);
    if (pin == 0xFFFF) {
        return (PLUM_ECODE_EPARA);
    }

    if (HAL_OK !=
        HAL_GPIO_WritePin(GPIOx, pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET)) {
        return (PLUM_ECODE_UNK);
    }

    return (PLUM_ECODE_OK);
}

plum_bit plum_hal_gpio_read(plum_u32 id)
{
    GPIO_TypeDef *GPIOx = gpio_id2port(id);
    if (!GPIOx) {
        return false;
    }

    uint16_t pin = gpio_id2pin(id);
    if (pin == 0xFFFF) {
        return false;
    }

    return ((HAL_GPIO_ReadPin(GPIOx, pin) == GPIO_PIN_SET) ? true : false);
}

/****************************************************************************/
/*                                                                          */
/*  End of file.                                                            */
/*                                                                          */
/****************************************************************************/
